/**
	This file is part of MemoryTrace.

	MemoryTrace is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

    Contributed by Ameziane NAIT ABDELAZIZ and Bruno LATHUILIERE at EDF R&D 
	SINECTICS I23 Clamart.
        
	MemoryTrace is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with MemoryTrace.  If not, see <http://www.gnu.org/licenses/>.
**/



/*! \file DumperStatusProc.h
    \brief Une implementation d'un dumper permettant d'extraire les 
    informations sur l'etat d'un processus.    
*/
#ifndef __DumperStatusProc__
#define __DumperStatusProc__

#include "Dumper.h"
#include <unistd.h>
#include <cassert>
#include <strings.h>
#include <cstring>


using namespace std;

#define PROC "/proc/"
#define VmSize "VmSize"
#define VmPeak "VmPeak" 
#define VmStk  "VmStk"
#define VmLib  "VmLib"
#define VmExe  "VmExe"
#define VmData "VmData"
#define VmRSS  "VmRSS"
#define VmHWM  "VmHWM"



/**
 *\brief structure de donnees stockant les informations issues du noyau
 * concernant un processus.
 */   
typedef struct
{
  /**
   * taille en memoire virtuelle du processus.
   */
  unsigned int vmSize;
  
  /**
   * pick en memoire virtuelle.
   */
  unsigned int vmPeak;
  
  /**
   * taille de la pile en memoire virtuelle.
   */	
  unsigned int vmStk;
  
  /**
   * taille du code des bibliotheques dynamiques.
   */
  unsigned int vmLib;
  
  /**
   * taille du segment de code du processus appelant.
   */
  unsigned int vmExe;

  /**
   *taille du segment de donnees du processus appelant.
   */
  unsigned int vmData;

  /**
   *taille de la memoire residente du processus appelant.
   */
  unsigned int vmRSS;
  
  /**
   *peak en memoire residente.
   */
  unsigned int vmHWM;

  /**
   *pid du processus appelant.
   */
  unsigned int Pid;
  string ProcFile;      
} status_t;



static void  getSizeFromString( char const * const  endLine, unsigned int & size  )
{
  int n=0;
  n=sscanf( endLine , "%u", &size );
  assert( n!=EOF && n!=0 );	
} 

static void  readStatus(status_t & status)
{
  std::string line;
  int k=0;
  std::ifstream statusFile(status.ProcFile.c_str(), std::ios::in);
  
  if(statusFile)
    {
      k=0;
      while ( getline(statusFile, line) && (k<10) ){
	if ( strncmp( line.c_str(), "VmSize:", 7 ) == 0 ){
	  getSizeFromString( line.c_str()+7, status.vmSize );
	  ++k;
	}				
	else if ( strncmp( line.c_str(), "VmPeak:", 7 ) == 0 ){
	  getSizeFromString( line.c_str()+7,status.vmPeak );
	  ++k;
	}
	else if ( strncmp( line.c_str(), "VmStk:", 6 ) == 0 ){
	  getSizeFromString( line.c_str()+6,status.vmStk );
	  ++k;
	}
	else if ( strncmp( line.c_str(), "VmLib:", 6 ) == 0 ){
	  getSizeFromString( line.c_str()+6,status.vmLib );
	  ++k;
	}
	else if ( strncmp( line.c_str(), "VmExe:", 6 ) == 0 ){
	      getSizeFromString( line.c_str()+6,status.vmExe );
	      ++k;
	    }
	else if ( strncmp( line.c_str(), "VmData:", 7 ) == 0 ){
	  getSizeFromString( line.c_str()+7,status.vmData );
	  ++k;
	}
	else if ( strncmp( line.c_str(), "VmRSS:", 6 ) == 0 ){
	  getSizeFromString( line.c_str()+6,status.vmRSS );
	  ++k;
	}
	else if ( strncmp( line.c_str(), "VmHWM:", 6 ) == 0 ){
	  getSizeFromString( line.c_str()+6,status.vmHWM );
	  ++k;
	}
      }
    }
  statusFile.close();
}


#define UNITE 1024 //(MB)
/**
 *\brief Permet de dumper les informations status issues du noyau.
 *\class DumperStatusProc 
 */
class DumperStatusProc:public Dumper<status_t>
{ 
 public:
  
  DumperStatusProc():Dumper<status_t>("status.out"){
    instance.Pid = (unsigned int) getpid();
    stringstream proc_file (stringstream::in | stringstream::out);
    proc_file << PROC << instance.Pid <<"/status";
    instance.ProcFile=proc_file.str();
    cout << "Profiling du processus "<<instance.Pid <<" par {/proc/pid/status}"<<endl;		    			  
  }
  
  DumperStatusProc(unsigned int pid):Dumper<status_t>("status.out"){
    instance.Pid = pid;
    stringstream proc_file (stringstream::in | stringstream::out);
    proc_file << PROC << instance.Pid <<"/status";
    instance.ProcFile=proc_file.str();
    cout << "Profiling du processus "<<instance.Pid <<" par {/proc/pid/status}"<<endl;		    			  
  }

  virtual void readLine(){
    /*mettre ss en variable d'instance et dans la méthode readAndDump faire un clear avant le read de ss*/
    stringstream ss (stringstream::in | stringstream::out);
    
    
    
    /*Lecture du status exporté par le noyau*/
    readStatus(instance);
    
    /*Construction du la ligne à dumper*/
    ss << this->temps     << ESPACE;
    ss << instance.vmSize/UNITE << ESPACE << instance.vmPeak/UNITE << ESPACE ;
    ss << instance.vmLib/UNITE  << ESPACE << instance.vmExe/UNITE  << ESPACE ;
    ss << instance.vmData/UNITE << ESPACE << instance.vmRSS/UNITE  << ESPACE << instance.vmHWM/UNITE ;
    
    /*Cet appel doit être factorisé */
    this->lines.push_back(ss.str());
  }
  
  
  virtual void printMeasure(){
    readStatus(instance);
    cout << instance.vmSize/UNITE << ESPACE << instance.vmPeak/UNITE << ESPACE ;
    cout << instance.vmLib/UNITE  << ESPACE << instance.vmExe/UNITE  << ESPACE ;
    cout << instance.vmData/UNITE << ESPACE << instance.vmRSS/UNITE  << ESPACE << instance.vmHWM/UNITE <<endl;
  }
  
  /**
   *\brief retourne une structure decrivant le status du processus profile.
   *\seeAlso status_t
   */
  static status_t getStatus(){
    status_t st ;
    readStatus(st);
    return st;
  }
};



#endif
